package com.daffodil.flowable.controller;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.daffodil.core.annotation.Log;
import com.daffodil.core.annotation.Log.BusinessType;
import com.daffodil.core.controller.BaseController;
import com.daffodil.core.entity.JsonResult;
import com.daffodil.core.entity.Page;
import com.daffodil.core.entity.TableInfo;
import com.daffodil.core.exception.BaseException;
import com.daffodil.flowable.constant.FlowableConstant;
import com.daffodil.flowable.entity.ActCnDeployment;
import com.daffodil.flowable.entity.ActCnHistoricActivity;
import com.daffodil.flowable.entity.ActCnHistoricProcess;
import com.daffodil.flowable.entity.ActFlowSubmitAssignee;
import com.daffodil.flowable.entity.ActFlowSubmitParam;
import com.daffodil.flowable.service.IFlowableDiagramService;
import com.daffodil.flowable.service.IFlowableHandleService;
import com.daffodil.flowable.service.IFlowableModelService;
import com.daffodil.flowable.util.FlowableUtils;
import com.daffodil.system.entity.SysUser;
import com.daffodil.system.util.LoginUserUtils;
import com.daffodil.util.StringUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import springfox.documentation.annotations.ApiIgnore;

/**
 * 流程引擎实例API
 * @author yweijian
 * @date 2020年7月8日
 * @version 1.0
 * @description
 */
@Api(value = "流程引擎管理", tags = "流程引擎管理")
@RestController
@RequestMapping(FlowableConstant.API_CONTENT_PATH)
public class FlowableTaskController extends BaseController{
    
    @Autowired
    private IFlowableHandleService handleService;
    
    @Autowired
    private IFlowableModelService modelService;
    
    @Autowired
    private IFlowableDiagramService diagramService;
    
    @ApiOperation("分页查询当前用户发起的流程业务任务数据列表")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @SuppressWarnings("unchecked")
    @GetMapping("/task/list/myself/{process}")
    public TableInfo listMyself(ActCnHistoricProcess historicProcess, 
            @ApiParam(value = "流程状态", required = true, allowableValues = "unfinished,finished,completed") @PathVariable("process") String process, 
            Page page, 
            @ApiIgnore HttpServletRequest request) {
        initQuery(historicProcess, page);
        SysUser user = LoginUserUtils.getLoginUser(request);
        List<ActCnHistoricProcess> list = new ArrayList<ActCnHistoricProcess>();
        switch (process) {
            case FlowableConstant.TASK_UNFINISHED:
                // 当前用户发起的流程业务的待办任务
                list = handleService.selectMyselfProcessList(query, user, false, false);
                break;
            case FlowableConstant.TASK_FINISHED:
                // 当前用户发起的流程业务的经办任务（已办任务）
                list = handleService.selectMyselfProcessList(query, user, true, false);
                break;
            case FlowableConstant.TASK_COMPLETED:
                // 当前用户发起的流程业务的办结任务
                list = handleService.selectMyselfProcessList(query, user, true, true);
                break;
            default:
                break;
        }
        return initTableInfo(list, query);
    }
    
    @ApiOperation("分页查询流程业务任务数据列表")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @SuppressWarnings("unchecked")
    @GetMapping("/task/list/{process}")
    public TableInfo list(ActCnHistoricProcess historicProcess, 
            @ApiParam(value = "流程状态", required = true, allowableValues = "unfinished,finished,completed") @PathVariable("process") String process, 
            Page page, 
            @ApiIgnore HttpServletRequest request) {
        
        initQuery(historicProcess, page);
        SysUser user = LoginUserUtils.getLoginUser(request);
        List<ActCnHistoricProcess> list = new ArrayList<ActCnHistoricProcess>();
        switch (process) {
            case FlowableConstant.TASK_UNFINISHED:
                // 当前登录用户的待办任务
                list = handleService.selectUnfinishedProcessList(query, user);
                break;
            case FlowableConstant.TASK_FINISHED:
                // 当前登录用户的经办任务（已办任务）
                list = handleService.selectFinishedProcessList(query, user);
                break;
            case FlowableConstant.TASK_COMPLETED:
                // 所有用户的办结任务(查看所有办结任务，一般是给管理员使用)
                list = handleService.selectCompletedProcessList(query);
                break;
            default:
                break;
        }
        return initTableInfo(list, query);
    }
    
    @ApiOperation("根据流程发布deployId或流程模板标识modelKey获取流程模板信息")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/modeler/info")
    public JsonResult modelerInfo(@ApiParam(value = "流程发布ID") String deployId, @ApiParam(value = "流程模板标识") String modelKey, @ApiIgnore HttpServletRequest request) {
        ActCnDeployment deployment = null;
        if(StringUtils.isNotEmpty(deployId)) {
            deployment = modelService.selectModelDeployByDeployId(deployId);
        }
        if(StringUtils.isNotEmpty(modelKey)) {
            deployment = modelService.selectModelDeployByModelKey(modelKey);
        }
        if(deployment == null) {
            throw new BaseException(60001);
        }
        return JsonResult.success(deployment);
    }
    
    @ApiOperation("根据业务标识获取获取当前流程节点信息")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/current/node/{businessKey}")
    public JsonResult currentNode(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, @ApiIgnore HttpServletRequest request) {
        SysUser user = LoginUserUtils.getLoginUser(request);
        Task task = FlowableUtils.getCurrentTask(businessKey, user.getLoginName());
        FlowElement flowElement = FlowableUtils.getFlowNode(task);
        return JsonResult.success(flowElement);
    }
    
    @ApiOperation("根据业务标识获取流程办理记录信息")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/activitys/{businessKey}")
    public JsonResult activitys(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, @ApiIgnore HttpServletRequest request){
        List<ActCnHistoricActivity> activitys = handleService.selectHistoricActivityByBusinessKey(businessKey);
        return JsonResult.success(activitys);
    }
    
    @ApiOperation("根据业务标识获取当前流程节点的操作按钮")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping({"/task/buttons/{businessKey}", "/task/buttons"})
    public JsonResult buttons(@ApiParam(value = "流程业务标识") @PathVariable(value = "businessKey", required = false) String businessKey, @ApiIgnore HttpServletRequest request){
        SysUser user = LoginUserUtils.getLoginUser(request);
        Map<String, Boolean> result = handleService.buildProcessInstanceButton(businessKey, user);
        return JsonResult.success(result);
    }
    
    @ApiOperation("根据业务标识获取流程图")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/diagram/{businessKey}")
    public void diagram(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, @ApiIgnore HttpServletResponse response){
        try {
            InputStream in = diagramService.getFlowableDiagramByBusinessKey(businessKey);
            response.setHeader("Content-type", MediaType.IMAGE_PNG_VALUE);
            IOUtils.write(IOUtils.toByteArray(in), response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @ApiOperation("根据业务标识获取指定操作的下一环节的候选人员")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/next/assignee/{businessKey}/{handleId}/{nodeId}")
    public JsonResult nextAssignee(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, 
            @ApiParam(value = "流程操作标识", required = true) @PathVariable("handleId") String handleId, 
            @ApiParam(value = "环节节点标识", required = true) @PathVariable("nodeId") String nodeId, 
            @ApiIgnore HttpServletRequest request){
        
        SysUser user = LoginUserUtils.getLoginUser(request);
        List<SysUser> users = FlowableUtils.getNextNodeHandleUsers(businessKey, user.getLoginName(), handleId, nodeId);
        return JsonResult.success(users);
    }
    
    @ApiOperation("根据业务标识获取指定操作的下一环节的信息")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/next/nodes/{businessKey}/{handleId}")
    public JsonResult nextNodes(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, 
            @ApiParam(value = "流程操作标识", required = true) @PathVariable("handleId") String handleId, 
            @ApiIgnore HttpServletRequest request){
        
        SysUser user = LoginUserUtils.getLoginUser(request);
        List<FlowElement> flowElements = FlowableUtils.getNextFlowNodes(businessKey, user.getLoginName(), handleId);
        return JsonResult.success(flowElements);
    }
    
    @ApiOperation("根据业务标识获取下一环节的操作信息")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @GetMapping("/task/next/handles/{businessKey}")
    public JsonResult nextHandles(@ApiParam(value = "流程业务标识", required = true) @PathVariable("businessKey") String businessKey, @ApiIgnore HttpServletRequest request){
        SysUser user = LoginUserUtils.getLoginUser(request);
        List<Map<String, String>> handles = FlowableUtils.getNextHandles(businessKey, user.getLoginName());
        FlowElement currentNode = FlowableUtils.getCurrentFlowNode(businessKey, user.getLoginName());
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("businessKey", businessKey);
        result.put("handles", handles);
        result.put("currentNode", currentNode);
        return JsonResult.success(result);
    }
    
    @ApiOperation("流程启动")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @PostMapping("/task/start")
    @Log(title = "流程引擎管理", businessType = BusinessType.INSERT)
    public JsonResult start(@ApiParam(value = "流程实例参数") @RequestBody Map<String, Object> params, @ApiIgnore HttpServletRequest request) {
        //流程实例初始化
        String flowName = (String) params.get("flowName");
        if(StringUtils.isEmpty(flowName)) {
            throw new BaseException(60002);
        }
        String modelKey = (String) params.get("modelKey");
        if(StringUtils.isEmpty(modelKey)) {
            throw new BaseException(60003);
        }
        String businessKey = (String) params.get("businessKey");
        if(StringUtils.isEmpty(businessKey)) {
            throw new BaseException(60004);
        }
        SysUser user = LoginUserUtils.getLoginUser(request);
        String tenantId = (String) params.get("tenantId");
        String callbackId = (String) params.get("callbackId");
        String callbackType = (String) params.get("callbackType");
        String instanceId = FlowableUtils.startProcessInstanceByKey(flowName, tenantId, modelKey, businessKey, user.getLoginName(), callbackId, callbackType, params);
        params.put("instanceId", instanceId);
        return JsonResult.success(params);
    }
    
    @ApiOperation("流程办理")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @Log(title = "流程引擎管理", businessType = BusinessType.UPDATE)
    @PostMapping("/task/handle")
    public JsonResult handle(@RequestBody @Validated ActFlowSubmitParam param, @ApiIgnore HttpServletRequest request){
        
        SysUser user = LoginUserUtils.getLoginUser(request);
        param.setUserId(user.getLoginName());
        handleService.generalDirectHandle(param);
        //设置下一环节办理人员
        if(StringUtils.isNotEmpty(param.getAssignees())) {
            for(ActFlowSubmitAssignee assignee : param.getAssignees()) {
                handleService.changeTaskAssignee(param.getBusinessKey(), assignee.getNodeId(), assignee.getUserId());
            }
        }
        
        return JsonResult.success();
    }
    
    @ApiOperation("流程作废")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @PostMapping("/task/trash")
    @Log(title = "流程引擎管理", businessType = BusinessType.TRASH)
    public JsonResult trash(@RequestBody @Validated ActFlowSubmitParam param, @ApiIgnore HttpServletRequest request) {
        handleService.deleteProcessInstance(param.getBusinessKey());
        return JsonResult.success();
    }
    
    @ApiOperation("流程撤办")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @PostMapping("/task/back")
    @Log(title = "流程引擎管理", businessType = BusinessType.UPDATE)
    public JsonResult back(@RequestBody @Validated ActFlowSubmitParam param, @ApiIgnore HttpServletRequest request) {
        SysUser user = LoginUserUtils.getLoginUser(request);
        handleService.backProcessInstance(param.getBusinessKey(), user.getLoginName());
        return JsonResult.success();
    }
    
    @ApiOperation("流程驳回")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "登录授权令牌 Bearer token", paramType = "header", required = true)
    @PostMapping("/task/reject")
    @Log(title = "流程引擎管理", businessType = BusinessType.UPDATE)
    public JsonResult reject(@RequestBody @Validated ActFlowSubmitParam param, @ApiIgnore HttpServletRequest request) {
        SysUser user = LoginUserUtils.getLoginUser(request);
        param.setUserId(user.getLoginName());
        handleService.rejectProcessInstance(param.getBusinessKey(), param.getMessage(), param.getUserId());
        return JsonResult.success();
    }
    
}
